﻿using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MiniJob;
using MiniJob.RestClient;
using MiniJob.Worker;
using MiniJob.Worker.Host;
using MiniJob.Worker.Runtime;

namespace Microsoft.Extensions.DependencyInjection;

public static class MiniJobServiceCollectionExtensions
{
    public static void AddMiniJobs(this IServiceCollection? services, Action<MiniJobRuntimeOptions>? configure, ServiceLifetime lifetime = ServiceLifetime.Singleton)
    {
        ArgumentNullException.ThrowIfNull(services, nameof(services));

        // Routing, health checks and logging are required dependencies.
        services.AddRouting();
        services.AddHealthChecks();
        services.AddLogging();
        services.TryAddSingleton<ISystemMetricsCollector, SystemMetricsCollector>();
        services.AddHostedService<InitHost>();

        services.AddHttpClient(Global.DefaultHttpClientName)
            .ConfigurePrimaryHttpMessageHandler(() => NewMessageHandler(true));
        services.AddScoped<IRestClient, DefaultRestClient>();

        var jobRuntimeRegistration = new Func<IServiceProvider, MiniJobRuntime>(s =>
        {
            var options = s.GetRequiredService<IOptions<MiniJobRuntimeOptions>>().Value;
            var loggerFactory = s.GetRequiredService<ILoggerFactory>();
            var activatorFactory = s.GetRequiredService<JobActivatorFactory>();
            return new MiniJobRuntime(options, loggerFactory, activatorFactory);
        });

        switch (lifetime)
        {
            case ServiceLifetime.Scoped:
                services.TryAddScoped<JobActivatorFactory, DependencyInjectionJobActivatorFactory>();
                services.TryAddScoped<MiniJobRuntime>(jobRuntimeRegistration);
                break;
            case ServiceLifetime.Transient:
                services.TryAddTransient<JobActivatorFactory, DependencyInjectionJobActivatorFactory>();
                services.TryAddTransient<MiniJobRuntime>(jobRuntimeRegistration);
                break;
            default:
            case ServiceLifetime.Singleton:
                services.TryAddSingleton<JobActivatorFactory, DependencyInjectionJobActivatorFactory>();
                services.TryAddSingleton<MiniJobRuntime>(jobRuntimeRegistration);
                break;
        }

        if (configure != null)
        {
            services.Configure<MiniJobRuntimeOptions>(configure);
        }
    }

    static HttpClientHandler NewMessageHandler(bool alwaysTrustSsl)
    {
        var handler = new HttpClientHandler();
        if (alwaysTrustSsl)
        {
            handler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true;
        }

        return handler;
    }
}
